from typing import List, Optional
from uuid import UUID

from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, HTTPException

from fastapi_template.common.responses import CommonResp
from fastapi_template.containers import Container
from fastapi_template.domains.permission import (PermissionCreateDTO,
                                                 PermissionDTO,
                                                 PermissionFacade,
                                                 PermissionUpdateDTO)

router = APIRouter(prefix="/permissions", tags=["permissions"])


@router.post("", response_model=CommonResp[PermissionDTO])
@inject
async def create_permission(
    permission_data: PermissionCreateDTO,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[PermissionDTO]:
    """Create a new permission."""
    try:
        permission = await permission_facade.create_permission(permission_data)
        return CommonResp.ok(data=permission)
    except Exception as e:
        return CommonResp.fail(msg=str(e))


@router.get("", response_model=CommonResp[List[PermissionDTO]])
@inject
async def get_all_permissions(permission_facade: PermissionFacade = Depends(
    Provide[Container.permission_facade])) -> CommonResp[List[PermissionDTO]]:
    """Get all permissions."""
    permissions = await permission_facade.get_all_permissions()
    return CommonResp.ok(data=permissions)


@router.get("/{permission_id}",
            response_model=CommonResp[Optional[PermissionDTO]])
@inject
async def get_permission(
    permission_id: UUID,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[Optional[PermissionDTO]]:
    """Get permission by ID."""
    permission = await permission_facade.get_permission_by_id(permission_id)
    if not permission:
        raise HTTPException(status_code=404, detail="Permission not found")
    return CommonResp.ok(data=permission)


@router.put("/{permission_id}",
            response_model=CommonResp[Optional[PermissionDTO]])
@inject
async def update_permission(
    permission_id: UUID,
    permission_data: PermissionUpdateDTO,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[Optional[PermissionDTO]]:
    """Update permission information."""
    permission = await permission_facade.update_permission(
        permission_id, permission_data)
    if not permission:
        raise HTTPException(status_code=404, detail="Permission not found")
    return CommonResp.ok(data=permission)


@router.delete("/{permission_id}", response_model=CommonResp[bool])
@inject
async def delete_permission(
    permission_id: UUID,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[bool]:
    """Delete permission by ID."""
    success = await permission_facade.delete_permission(permission_id)
    if not success:
        raise HTTPException(status_code=404, detail="Permission not found")
    return CommonResp.ok(data=True)


@router.get("/role/{role_id}", response_model=CommonResp[List[PermissionDTO]])
@inject
async def get_role_permissions(
    role_id: UUID,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[List[PermissionDTO]]:
    """Get all permissions of a role."""
    permissions = await permission_facade.get_role_permissions(role_id)
    return CommonResp.ok(data=permissions)


@router.post("/role/{role_id}/permission/{permission_id}",
             response_model=CommonResp[bool])
@inject
async def assign_permission_to_role(
    role_id: UUID,
    permission_id: UUID,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[bool]:
    """Assign a permission to a role."""
    success = await permission_facade.assign_permission_to_role(
        role_id, permission_id)
    if not success:
        raise HTTPException(status_code=404,
                            detail="Role or permission not found")
    return CommonResp.ok(data=True)


@router.delete("/role/{role_id}/permission/{permission_id}",
               response_model=CommonResp[bool])
@inject
async def remove_permission_from_role(
    role_id: UUID,
    permission_id: UUID,
    permission_facade: PermissionFacade = Depends(
        Provide[Container.permission_facade])
) -> CommonResp[bool]:
    """Remove a permission from a role."""
    success = await permission_facade.remove_permission_from_role(
        role_id, permission_id)
    if not success:
        raise HTTPException(status_code=404,
                            detail="Role or permission not found")
    return CommonResp.ok(data=True)
